package com.informatics.polymer.client.PolymerTemplates;

import org.restlet.gwt.Callback;
import org.restlet.gwt.Client;
import org.restlet.gwt.data.Form;
import org.restlet.gwt.data.Protocol;
import org.restlet.gwt.data.Request;
import org.restlet.gwt.data.Response;
import org.restlet.gwt.resource.Representation;

import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.TextBox;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.Side;
import com.smartgwt.client.types.VisibilityMode;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.SectionStack;
import com.smartgwt.client.widgets.layout.SectionStackSection;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.TabSet;

/**
 * Class to implement a panel to build graft copolymers.
 * @author ed
 * @version 1.0
 */
public class GraftCopolymerPanel extends SectionStack implements InitializePolymerPanels {
	/**
	 * Integer representing the number of times the build button has been pressed.
	 */
	private int counter=-1;
	/**
	 * XML string representation of the built graft copolymer.
	 */
	private String graftCopolymerBuilt;
	/**
	 * Number of main chain repeat units.
	 */
	private int degreeofPolymerizationMain;
	/**
	 * Number of branch chain repeat units.
	 */
	private int degreeofPolymerizationBranch;
	/**
	 * Torsion angle for polymerization.
	 */
	private double torsionAngle;

	/**
	 * Constructs default block copolymer panel object.
	 */
	public GraftCopolymerPanel(){
		setUpPanel();
	}
	/**
	 * Sets up a tabset panel for graft copolymer submission, in order to build a 
	 * graft copolymer.
	 */
	@Override
	public TabSet detailsPanel() {
		final TabSet graftCopolymerDetails = new TabSet();
		graftCopolymerDetails.setBackgroundColor("#F0F0F0");
		graftCopolymerDetails.setTabBarPosition(Side.TOP);
		graftCopolymerDetails.setWidth(1000);
		graftCopolymerDetails.setHeight(200);
		Tab tTab1 = new Tab("Main Chain DP");
		Canvas tab1Canvas = new Canvas();
		tab1Canvas.setBackgroundColor("#F0F0F0");
		final TextBox tbDegreeOfPolymerization = new TextBox();
		tbDegreeOfPolymerization.setTitle("Degree of polymerization:");
		tab1Canvas.addChild(tbDegreeOfPolymerization);
		tTab1.setPane(tab1Canvas);
		Tab degreeOfPolymerisationBTab = new Tab("Branch Chain DP");
		Canvas degreeOfPolymerisationBCanvas = new Canvas();
		degreeOfPolymerisationBCanvas.setBackgroundColor("#F0F0F0");
		final TextBox degreeOfPolymerizationBTB = new TextBox();
		degreeOfPolymerizationBTB.setTitle("Degree of polymerization Branch Chain:");
		degreeOfPolymerisationBCanvas.addChild(degreeOfPolymerizationBTB);
		degreeOfPolymerisationBTab.setPane(degreeOfPolymerisationBCanvas);
		Tab tTab3 = new Tab("Main Chain");
		Canvas tab3Canvas = new Canvas();
		tab3Canvas.setBackgroundColor("#F0F0F0");
		final TextBox tbRepeatUnit = new TextBox();
		tbRepeatUnit.setTitle("Main Chain");
		tab3Canvas.addChild(tbRepeatUnit);
		tTab3.setPane(tab3Canvas);
		//Add repeat unit B
		Tab repeatUnitBTab = new Tab("Branch Chain");
		Canvas repeatUnitBCanvas = new Canvas();
		repeatUnitBCanvas.setBackgroundColor("#F0F0F0");
		final TextBox repeatUnitBTextBox = new TextBox();
		repeatUnitBTextBox.setTitle("Branch Chain");
		repeatUnitBCanvas.addChild(repeatUnitBTextBox);
		repeatUnitBTab.setPane(repeatUnitBCanvas);
		Tab tTab4 = new Tab("End Group 1");
		Canvas tab4Canvas = new Canvas();
		tab4Canvas.setBackgroundColor("#F0F0F0");
		final TextBox tbEndGroup1 = new TextBox();
		tbEndGroup1.setTitle("End Group 1");
		tab4Canvas.addChild(tbEndGroup1);
		tTab4.setPane(tab4Canvas);
		Tab tTab5 = new Tab("End Group 2");
		Canvas tab5Canvas = new Canvas();
		tab5Canvas.setBackgroundColor("#F0F0F0");
		final TextBox tbEndGroup2 = new TextBox();
		tbEndGroup2.setTitle("End Group 2");
		tab5Canvas.addChild(tbEndGroup2);
		tTab5.setPane(tab5Canvas);
		Tab tTab6 = new Tab("Build Graft Copolymer");
		HLayout horizontalLayout = new HLayout();
		Canvas tab6Canvas = new Canvas();
		tab6Canvas.setBackgroundColor("#F0F0F0");
		//Add a review submission button
		IButton reviewSubmissionButton = new IButton("Review Submission");
		reviewSubmissionButton.setLeft(0);
		reviewSubmissionButton.setHeight(30);
		reviewSubmissionButton.setWidth(150);
		reviewSubmissionButton.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				tbRepeatUnit.setText(callGetData());
				tbEndGroup1.setText(callGetEndGroup1());
				tbEndGroup2.setText(callGetEndGroup2());
				repeatUnitBTextBox.setText(callGetBranchChain());
			}
			
		});
		tab6Canvas.addChild(reviewSubmissionButton);
		//Add a build polymer button
		IButton buildPolymerButton =  new IButton("Build Polymer");
		buildPolymerButton.setLeft(160);
		buildPolymerButton.setHeight(30);
		buildPolymerButton.setWidth(150);
		//Add restlet code here.
		buildPolymerButton.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				counter++;
				int repeatUnitRCount =  countNumberofFragmentPoints(callGetData(),"[Pr]");
				int endGroup1RCount = countNumberofFragmentPoints(callGetEndGroup1(),"[Pr]");
				int endGroup2RCount = countNumberofFragmentPoints(callGetEndGroup2(),"[Pr]");	
				int repeatUnitBRCount = countNumberofFragmentPoints(callGetBranchChain(),"[Pr]");
				if(repeatUnitRCount != 2 || endGroup1RCount != 1 || endGroup2RCount != 1){
					com.google.gwt.user.client.Window.alert("Please check the number of Pr atoms!");
				}
				if(repeatUnitRCount >= 2 && repeatUnitBRCount == 2 && endGroup1RCount == 1 && endGroup2RCount == 1){
					com.google.gwt.user.client.Window.alert("Processing polymer!");
					try {
						setDegreeofPolymerizationMain(Integer.parseInt(tbDegreeOfPolymerization.getText()));
					} catch (NumberFormatException nfe) {
						com.google.gwt.user.client.Window.alert("You need to enter an integer for degree of polymerization > 0!");
					}
					try{
						setDegreeofPolymerizationBranch(Integer.parseInt(degreeOfPolymerizationBTB.getText()));
					}
					catch(NumberFormatException nfe){
						com.google.gwt.user.client.Window.alert("You need to  enter an integer for  the degree of polymerization > 0!");
					}
					//Need to add restlet code here to process the polymer.
					//Replace [Pr] with [R]
					String endGroup1 = callGetEndGroup1().replace("[Pr]", "[R]");
					String repeatUnit = callGetData().replace("[Pr]", "[R]");
					String repeatUnitBranchChain = callGetBranchChain().replace("[Pr]", "[R]");
					String endGroup2 = callGetEndGroup2().replace("[Pr]", "[R]");
					
					com.google.gwt.user.client.Window.alert(endGroup1);
					com.google.gwt.user.client.Window.alert(repeatUnit);
					com.google.gwt.user.client.Window.alert(repeatUnitBranchChain);
					com.google.gwt.user.client.Window.alert(endGroup2);
					
					final Client client = new Client(Protocol.HTTP);
					Form form = new Form();
					form.add("degreeOfPolymerisationMain",tbDegreeOfPolymerization.getText());
					form.add("degreeOfPolymerisationBranch",degreeOfPolymerizationBTB.getText());
					form.add("endGroup1", endGroup1);
					form.add("repeatUnit", repeatUnit);
					form.add("repeatUnitBranch",repeatUnitBranchChain);
					form.add("endGroup2", endGroup2);
					form.add("counter",Integer.toString(counter));
					Representation rep = form.getWebRepresentation();
					client.post("http://localhost:8080/svc/graftCopolymer", rep, new Callback() {
					
						@Override
						public void onEvent(Request request, Response response) {
							String resultantText = response.getEntity().getText();
							com.google.gwt.user.client.Window.alert(resultantText);
							resultantText = resultantText.replace("\n", "");
							setGraftCopolymerBuilt(resultantText);
							String jmolApplet = " <applet name=\"jmol1\" code=\"JmolApplet\" archive=\"JmolApplet.jar\" width=\"450\" height=\"450\" align=\"right\"> "+
							" <param name = \"progressbar\" value = \"true\"/>"+
							"<param name=\"load\" value=\"GraftCopolymer0.cml\"/> </applet>";
							HTMLFlow jmolHTML = new HTMLFlow();
							jmolHTML.setOverflow(Overflow.AUTO);
							jmolHTML.setPadding(10);
							jmolHTML.setContents(jmolApplet);
							Tab ttt = new Tab("JMOL Result");
							Canvas tab7Canvas = new Canvas();
							tab7Canvas.setBackgroundColor("#F0F0F0");
							tab7Canvas.addChild(jmolHTML);
							ttt.setPane(tab7Canvas);
							graftCopolymerDetails.addTab(ttt);

						}});

			
				}
			}	
		});		
	
		horizontalLayout.addChild(buildPolymerButton);
		tab6Canvas.addChild(buildPolymerButton);
		tab6Canvas.addChild(new HTML("<br></br><br></br>Press the <I>\"Review Submission\"</I> button to check the input before polymerization, then press the <I>\"Build Polymer\"</I> button to build the polymer." +
		"<br></br> Then please visit the visualization panel to view the built polymer."));
		tTab6.setPane(tab6Canvas);
		graftCopolymerDetails.addTab(tTab1);
		graftCopolymerDetails.addTab(degreeOfPolymerisationBTab);
		graftCopolymerDetails.addTab(tTab3);
		graftCopolymerDetails.addTab(repeatUnitBTab);
		graftCopolymerDetails.addTab(tTab4);
		graftCopolymerDetails.addTab(tTab5);
		graftCopolymerDetails.addTab(tTab6);
		return graftCopolymerDetails;

	}

	@Override
	public void setUpPanel() {
		this.setVisibilityMode(VisibilityMode.MULTIPLE);
		this.setWidth(1000);
		this.setHeight(500);
		this.setBorder("2px solid #458B00");
		SectionStackSection section1 = new SectionStackSection("Graft Copolymer");
		section1.setExpanded(true);
		HTMLFlow welcome = new HTMLFlow();
		welcome.setOverflow(Overflow.AUTO);
		welcome.setPadding(10);
		String welcomeString = "Welcome to the graft copolymer builder panel, please see the instructions tab "+
		"below for more details on what a graft copolymer is, and how to build a graft copolymer.";
		welcome.setContents(welcomeString);
		section1.addItem(welcome);
		this.addSection(section1);
		this.setStyleName("sectionHeaderclosed");
		this.setBackgroundColor("#F0F0F0");
		//Add drawing panel
		final SectionStackSection drawingPanel = new SectionStackSection("Drawing Panel");
		HTMLFlow drawingPanelInfo = new HTMLFlow();
		drawingPanelInfo.setOverflow(Overflow.AUTO);
		drawingPanelInfo.setPadding(10);
		drawingPanel.setExpanded(false);
		drawingPanel.addItem(jchemPaintPanel());
		this.addSection(drawingPanel);
		//Add homopolymer details panel - submission.
		TabSet details = detailsPanel();
		SectionStackSection infoToSubmit = new SectionStackSection("Submission Details");
		infoToSubmit.setExpanded(false);
		infoToSubmit.addItem(details);
		this.addSection(infoToSubmit);
		//Visualization panel
		SectionStackSection visualizationPanel = VisualizationPanel();
		this.addSection(visualizationPanel);
		//Add instructions tab.
		SectionStackSection instructionSection = new SectionStackSection("Instructions");
		instructionSection.setExpanded(false);
		HTMLFlow graftCopolymerInstructions = new HTMLFlow();
		graftCopolymerInstructions.setOverflow(Overflow.AUTO);
		graftCopolymerInstructions.setPadding(10);
		String instructions ="Graft copolymers are defined as: Any polymer whose configuration consists of many homopolymeric branches joined or grafted to another homopolymer. <br></br>"+
		"<b> Instructions</b> <br></br>"+
		"1. Using the drawing panel, you can draw structures of the repeat units A and B and end groups 1 and 2.<br></br>"+
		" <b>Remember</b><br></br> Repeat units have two R groups. To create branches you need to have preferably around 4 R groups for each repeat unit.<br></br> "+
		"End groups have one R group.<br></br>"+
		"2. <b>Submission Panel</b><br></br>" +
		"The submission panel gives information on the: degree of polymerization, torsion angle and the repeat units and end groups used. To build the graft copolymer"+
		" go to the <I>\"Build graft copolymer</I>\" tab and press the build polymer button, this will build your requested polymer.<br></br> "+
		"3. <b>Visualization Panel </b><br></br> Please visit the visualization panel when you have submitted your polymer, as the resultant polymer can be visualized there.<br></br>"+
		"4. <b>Delete Panel</b><br></br> If you are not happy with your selection or choose to build another polymer you can click on the <I>\"Delete Panel\"</I> and press the delete panel button"+
		" this will delete the graft copolymer panel, so you can start over again.<br></br>"+
		"<b>Terminology</b><br></br>"+
		"<I>Degree of polymerization</I>:the number of repeat units in an average polymer chain at time t in a polymerization reaction. Ref: http://en.wikipedia.org/wiki/Degree_of_polymerization. Accessed: 09/09/09<br></br>"+
		"<I>Torsion angle</I>: the angle between two planes. Ref: http://en.wikipedia.org/wiki/Dihedral_angle. Accessed: 09/09/09<br></br>"+
		"<I>Repeat unit</I>: the repeat unit is the simplest structural entity of a polymer chain. Ref: http://en.wikipedia.org/wiki/Repeat_unit. Accessed: 09/09/09<br></br>"+
		"<I>End group</I>: is a constitutional unit that is an extremity of a macromolecule or oligomer molecule. Ref: http://en.wikipedia.org/wiki/End-group. Accessed: 09/09/09";
		graftCopolymerInstructions.setContents(instructions);
		instructionSection.addItem(graftCopolymerInstructions);
		this.addSection(instructionSection);
		//Delete panel section
		SectionStackSection deletePanelSection = new SectionStackSection("Delete Panel");
		deletePanelSection.setExpanded(false);
		Button deletePanelButton = new Button("Delete Panel!");
		deletePanelButton.setSize("100", "30");
		deletePanelButton.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				destroy();
			}
		});
	   deletePanelSection.addItem(deletePanelButton);
	   this.addSection(deletePanelSection);

	}

	/**
	 * TabSet panel for JChempaint
	 * @return TabSet - tabs containing jchemPaint applets.
	 */
	private TabSet jchemPaintPanel(){
		TabSet drawingPanels = new TabSet();
		drawingPanels.setBackgroundColor("#F0F0F0");
		drawingPanels.setTabBarPosition(Side.TOP);
		drawingPanels.setWidth(1000);
		drawingPanels.setHeight(500);
		//Add separate panes.
		Tab tMainChainTab = new Tab("Main Chain");
		Canvas tab1Canvas = new Canvas();
		tab1Canvas.setBackgroundColor("#F0F0F0");
		String appletCode = "<br></br>  <applet code=\"org.openscience.cdk.applications.jchempaint.applet.JChemPaintEditorApplet\" archive=\"jchempaint-applet-core.jar\" name=\"applet\" width=\"450\" height=\"375\">"+"</applet>";
		tab1Canvas.setContents(appletCode);
		tMainChainTab.setPane(tab1Canvas);
		//Add repeat unit B tab.
		Tab tTabBranchChain = new Tab("Branch Chain");
		Canvas tabrepeatUnitBCanvas = new Canvas();
		tabrepeatUnitBCanvas.setBackgroundColor("#F0F0F0");
		String appletCodeRepeatUnitB = "<br></br>  <applet code=\"org.openscience.cdk.applications.jchempaint.applet.JChemPaintEditorApplet\" archive=\"jchempaint-applet-core.jar\" name=\"branchChain\" width=\"450\" height=\"375\">"+"</applet>";
		tabrepeatUnitBCanvas.setContents(appletCodeRepeatUnitB);
		tTabBranchChain.setPane(tabrepeatUnitBCanvas);
		//Add End Group 1 tab.
		Tab tTab2 =  new Tab("End Group 1");
		Canvas tab2Canvas = new Canvas();
		tab2Canvas.setBackgroundColor("#F0F0F0");
		String endGroup1Applet = "<br></br> <applet code=\"org.openscience.cdk.applications.jchempaint.applet.JChemPaintEditorApplet\" archive=\"jchempaint-applet-core.jar\" name=\"endgroup1\" width=\"450\" height=\"375\">"+"</applet>";
		tab2Canvas.setContents(endGroup1Applet);
		tTab2.setPane(tab2Canvas);
		//Add End Group 2 tab.
		Tab tTab3 = new Tab("End Group 2");
		Canvas tab3Canvas = new Canvas();
		tab3Canvas.setBackgroundColor("#F0F0F0");
		String endGroup2Applet = "<br></br> <applet code=\"org.openscience.cdk.applications.jchempaint.applet.JChemPaintEditorApplet\" archive=\"jchempaint-applet-core.jar\" name=\"endGroup2\" width=\"450\" height=\"375\">"+"</applet>";
		tab3Canvas.setContents(endGroup2Applet);
		tTab3.setPane(tab3Canvas);
		drawingPanels.addTab(tMainChainTab);
		drawingPanels.addTab(tTabBranchChain);
		drawingPanels.addTab(tTab2);
		drawingPanels.addTab(tTab3);
		return drawingPanels;
	}

	/**
	 * Set up the visualization panel, this will involve the use of JMol.
	 * @return SectionStackSection - section for the visualization panel for Jmol.
	 */
	private SectionStackSection VisualizationPanel(){
		SectionStackSection visualizationSection = new SectionStackSection("Visualization Panel");
		visualizationSection.setExpanded(false);
		String jmolApplet = " <applet name=\"jmol\" code=\"JmolApplet\" archive=\"JmolApplet.jar\" width=\"250\" height=\"250\" align=\"right\"> "+
		" <param name = \"progressbar\" value = \"true\"/>"+
		"<param name=\"load\" value=\"GraftCopolymer0.cml\"/> </applet>";
		HTMLFlow jmolHTML = new HTMLFlow();
		jmolHTML.setOverflow(Overflow.AUTO);
		jmolHTML.setPadding(10);
		jmolHTML.setContents(jmolApplet);
		visualizationSection.addItem(jmolHTML);
		String graftCopolymerSourceLink = "<a href=\"http://localhost:8080/GraftCopolymer0.cml\">CML Source</a>";
		HTMLFlow blockCopolymerSource =  new HTMLFlow();
		blockCopolymerSource.setContents(graftCopolymerSourceLink);
		visualizationSection.addItem(blockCopolymerSource);
		return visualizationSection;
	}
	
	/**
	 * Native javascript method to  invoke the DOM and extract smile strings from JchemPaint
	 * @return String representation of the repeat unit.
	 */
	private native String callGetData() /*-{
	   var smileString;
	   smileString = $doc.applet.getSmiles();
	   return smileString;
	    }-*/;
	
	private native String callGetBranchChain() /*-{
		var smileString;
		smileString =  $doc.branchChain.getSmiles();
		return smileString;
	}-*/;
	/**
	 * Native method to return endgroup 1 smile string from JChempaint.
	 * @return String representation of end group1.
	 */
	private native String callGetEndGroup1() /*-{
		var endGroup1;
		endGroup1 = $doc.endgroup1.getSmiles();
		return endGroup1;
		}-*/;
	
	/**
	 * Native method to return endgroup 1 smile string from JChempaint.
	 * @return String representation of end group1.
	 */
	private native String callGetEndGroup2() /*-{
		var endGroup2;
		endGroup2 = $doc.endGroup2.getSmiles();
		return endGroup2;
		}-*/;
	
	/**
	 * This method checks the number of R atoms drawn for the repeat units and end groups in JChempaint.
	 * @param text - R group value [R].
	 * @param search - Smile string to search.
	 * @return - int value representing the number of R groups in a molecule.
	 */
	private int countNumberofFragmentPoints(final String text, final String search){
		 int count = 0;
		 for (int fromIndex = 0; fromIndex > -1; count++){
			 fromIndex = text.indexOf(search, fromIndex + ((count > 0) ? 1 : 0));
		 }   
		    return count - 1;
	}
	/**
	 * @param graftCopolymerBuilt the graftCopolymerBuilt to set
	 */
	public void setGraftCopolymerBuilt(final String graftCopolymerBuilt) {
		this.graftCopolymerBuilt = graftCopolymerBuilt;
	}
	/**
	 * @return the graftCopolymerBuilt
	 */
	public String getGraftCopolymerBuilt() {
		return graftCopolymerBuilt;
	}
	/**
	 * @param degreeofPolymerizationMain the degreeofPolymerizationMain to set
	 */
	public void setDegreeofPolymerizationMain(final int degreeofPolymerizationMain) {
		this.degreeofPolymerizationMain = degreeofPolymerizationMain;
	}
	/**
	 * @return the degreeofPolymerizationMain
	 */
	public int getDegreeofPolymerizationMain() {
		return degreeofPolymerizationMain;
	}
	/**
	 * @param degreeofPolymerizationBranch the degreeofPolymerizationBranch to set
	 */
	public void setDegreeofPolymerizationBranch(final int degreeofPolymerizationBranch) {
		this.degreeofPolymerizationBranch = degreeofPolymerizationBranch;
	}
	/**
	 * @return the degreeofPolymerizationBranch
	 */
	public int getDegreeofPolymerizationBranch() {
		return degreeofPolymerizationBranch;
	}
	/**
	 * @param torsionAngle the torsionAngle to set
	 */
	public void setTorsionAngle(final double torsionAngle) {
		this.torsionAngle = torsionAngle;
	}
	/**
	 * @return the torsionAngle
	 */
	public double getTorsionAngle() {
		return torsionAngle;
	}

}
